﻿using System.Collections.Generic;

using Godot.core.os;
using Godot.core.math;

namespace Godot.core
{
    public partial class Variant
    {
        private object _data;
        
        private Type _type;

        public object data
        {
            get { return _data; }
        }
        
        public Type type
        {
            get
            {
                return _type;
            }
        }

        #region ____constructors____
        public Variant()
        {
            _data = null;
            _type = Variant.Type.NIL;
        }

        public Variant(Variant variant)
        {
            _data = variant._data;
            _type = variant._type;
        }

        public Variant(bool p_arg)
        {
            _type = Variant.Type.BOOL;
            _data = p_arg;
        }

        public Variant(int p_arg)
        {
            _type = Variant.Type.INT;
            _data = p_arg;
        }

        public Variant(uint p_arg)
        {
            _type = Variant.Type.INT;
            _data = p_arg;
        }
        
        public Variant(long p_arg)
        {
            _type = Variant.Type.INT;
            _data = p_arg;
        }

        public Variant(ulong p_arg)
        {
            _type = Variant.Type.INT;
            _data = p_arg;
        }

        public Variant(double p_arg)
        {
            _type = Variant.Type.REAL;
            _data = p_arg;
        }

        public Variant(string p_arg)
        {
            _type = Variant.Type.STRING;
            _data = p_arg;
        }

        public Variant(StringName p_arg)
        {
            _type = Variant.Type.STRING;
            _data = p_arg;
        }

        public Variant(NodePath p_arg)
        {
            _type = Variant.Type.NODE_PATH;
            _data = p_arg;
        }

        public Variant(Rect2 p_arg)
        {
            _type = Variant.Type.RECT2;
            _data = p_arg;
        }

        public Variant(Vector2 p_arg)
        {
            _type = Variant.Type.VECTOR2;
            _data = p_arg;
        }

        public Variant(Vector3 p_arg)
        {
            _type = Variant.Type.VECTOR3;
            _data = p_arg;
        }

        public Variant(Matrix3 p_arg)
        {
            _type = Variant.Type.MATRIX3;
            _data = p_arg;
        }

        public Variant(Plane p_arg)
        {
            _type = Variant.Type.PLANE;
            _data = p_arg;
        }

        public Variant(Quat p_arg)
        {
            _type = Variant.Type.QUAT;
            _data = p_arg;
        }

        public Variant(Aabb p_arg)
        {
            _type = Variant.Type.AABB;
            _data = p_arg;
        }

        public Variant(Transform p_arg)
        {
            _type = Variant.Type.TRANSFORM;
            _data = p_arg;
        }

        public Variant(Object p_arg)
        {
            _type = Variant.Type.OBJECT;
            _data = p_arg;
        }

        public Variant(InputEvent p_arg)
        {
            _type = Type.INPUT_EVENT;
            _data = p_arg;
        }

        public Variant(List<Variant> p_arg)
        {
            _type = Variant.Type.ARRAY;
            _data = p_arg;
        }

        public Variant(List<string> p_arg)
        {
            _type = Variant.Type.STRING_ARRAY;
            _data = p_arg;
        }

        public Variant(List<byte> p_arg)
        {
            _type = Variant.Type.RAW_ARRAY;
        }

        public Variant(List<int> p_arg)
        {
            _type = Variant.Type.INT_ARRAY;
            _data = p_arg;
        }

        public Variant(List<double> p_arg)
        {
            _type = Variant.Type.REAL_ARRAY;
            _data = p_arg;
        }

        public Variant(List<float> p_arg)
        {
            _type = Variant.Type.REAL_ARRAY;
            _data = p_arg;
        }

        public Variant(List<Vector3> p_arg)
        {
            _type = Variant.Type.VECTOR3_ARRAY;
            _data = p_arg;
        }

        public Variant(List<Color> p_arg)
        {
            _type = Variant.Type.COLOR_ARRAY;
            _data = p_arg;
        }

        public Variant(Dictionary<Variant, Variant> p_arg)
        {
            _type = Variant.Type.DICTIONARY;
            _data = p_arg;
        }

        public Variant(Color p_arg)
        {
            _type = Variant.Type.COLOR;
            _data = p_arg;
        }

        public Variant(Image p_arg)
        {
            _type = Variant.Type.IMAGE;
            _data = p_arg;
        }
        #endregion

        #region ____to_Variant_conversion____
        public static implicit operator Variant(bool num)
        {
            return new Variant(num);
        }

        public static implicit operator Variant(int num)
        {
            return new Variant(num);
        }

        public static implicit operator Variant(long num)
        {
            return new Variant(num);
        }

        public static implicit operator Variant(double num)
        {
            return new Variant(num);
        }

        public static implicit operator Variant(string str)
        {
            return new Variant(str);
        }

        public static implicit operator Variant(StringName str)
        {
            return new Variant(str);
        }

        public static implicit operator Variant(NodePath np)
        {
            return new Variant(np);
        }

        public static implicit operator Variant(Rect2 p_arg)
        {
            return new Variant(p_arg);
        }

        public static implicit operator Variant(Vector2 p_arg)
        {
            return new Variant(p_arg);
        }

        public static implicit operator Variant(Vector3 p_arg)
        {
            return new Variant(p_arg);
        }

        public static implicit operator Variant(Matrix3 p_arg)
        {
            return new Variant(p_arg);
        }

        public static implicit operator Variant(Plane p_arg)
        {
            return new Variant(p_arg);
        }

        public static implicit operator Variant(Quat p_arg)
        {
            return new Variant(p_arg);
        }

        public static implicit operator Variant(Aabb p_arg)
        {
            return new Variant(p_arg);
        }

        public static implicit operator Variant(Transform p_arg)
        {
            return new Variant(p_arg);
        }

        public static implicit operator Variant(Object p_arg)
        {
            return new Variant(p_arg);
        }

        public static implicit operator Variant(InputEvent p_arg)
        {
            return new Variant(p_arg);
        }

        public static implicit operator Variant(List<Variant> p_arg)
        {
            return new Variant(p_arg);
        }

        public static implicit operator Variant(List<string> p_arg)
        {
            return new Variant(p_arg);
        }

        public static implicit operator Variant(List<byte> p_arg)
        {
            return new Variant(p_arg);
        }

        public static implicit operator Variant(List<int> p_arg)
        {
            return new Variant(p_arg);
        }

        public static implicit operator Variant(List<double> p_arg)
        {
            return new Variant(p_arg);
        }

        public static implicit operator Variant(List<float> p_arg)
        {
            return new Variant(p_arg);
        }

        public static implicit operator Variant(List<Vector3> p_arg)
        {
            return new Variant(p_arg);
        }

        public static implicit operator Variant(List<Color> p_arg)
        {
            return new Variant(p_arg);
        }

        public static implicit operator Variant(Dictionary<Variant, Variant> p_arg)
        {
            return new Variant(p_arg);
        }

        public static implicit operator Variant(Color p_arg)
        {
            return new Variant(p_arg);
        }

        public static implicit operator Variant(Image p_arg)
        {
            return new Variant(p_arg);
        }
        #endregion

        #region ____from_Variant_conversion____
        public static implicit operator bool(Variant v)
        {
            return (bool)v._data;
        }

        public static implicit operator int(Variant v)
        {
            return (int)v._data;
        }

        public static implicit operator long(Variant v)
        {
            return (long)v._data;
        }

        public static implicit operator double(Variant v)
        {
            return (double)v._data;
        }

        public static implicit operator string(Variant v)
        {
            return (string)v._data;
        }

        public static implicit operator StringName(Variant v)
        {
            return (StringName)v._data;
        }

        public static implicit operator NodePath(Variant v)
        {
            return v._data as NodePath;
        }

        public static implicit operator Rect2(Variant v)
        {
            return (Rect2)v._data;
        }

        public static implicit operator Vector2(Variant v)
        {
            return (Vector2)v._data;
        }

        public static implicit operator Vector3(Variant v)
        {
            return (Vector3)v._data;
        }

        public static implicit operator Matrix3(Variant v)
        {
            return (Matrix3)v._data;
        }

        public static implicit operator Plane(Variant v)
        {
            return (Plane)v._data;
        }

        public static implicit operator Quat(Variant v)
        {
            return (Quat)v._data;
        }

        public static implicit operator Aabb(Variant v)
        {
            return (Aabb)v._data;
        }

        public static implicit operator Transform(Variant v)
        {
            return (Transform)v._data;
        }

        public static implicit operator Object(Variant v)
        {
            return (Object)v._data;
        }

        public static implicit operator InputEvent(Variant v)
        {
            return (InputEvent)v._data;
        }

        public static implicit operator List<Variant>(Variant v)
        {
            return (List<Variant>)v._data;
        }

        public static implicit operator List<string>(Variant v)
        {
            return (List<string>)v._data;
        }

        public static implicit operator List<byte>(Variant v)
        {
            return (List<byte>)v._data;
        }

        public static implicit operator List<int>(Variant v)
        {
            return (List<int>)v._data;
        }

        public static implicit operator List<double>(Variant v)
        {
            return (List<double>)v._data;
        }

        public static implicit operator List<float>(Variant v)
        {
            return (List<float>)v._data;
        }

        public static implicit operator List<Vector3>(Variant v)
        {
            return (List<Vector3>)v._data;
        }

        public static implicit operator List<Color>(Variant v)
        {
            return (List<Color>)v._data;
        }

        public static implicit operator Dictionary<Variant, Variant>(Variant v)
        {
            return (Dictionary<Variant, Variant>)v._data;
        }

        public static implicit operator Color(Variant v)
        {
            return (Color)v._data;
        }

        public static implicit operator Image(Variant v)
        {
            return (Image)v._data;
        }
        #endregion

        public override bool Equals(object obj)
        {
            if (obj is Variant)
            {
                if (_type != (obj as Variant)._type) 
                    return false;
                
                return _data.Equals((obj as Variant)._data);
            }
            else
            {
                return _data.Equals(obj);
            }
        }

        public override int GetHashCode()
        {
            return _data.GetHashCode();
        }
    }
}
